package com.study.es;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.HttpHost;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkItemResponse;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.client.indices.GetIndexResponse;
import org.elasticsearch.common.unit.Fuzziness;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.metrics.AvgAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.MaxAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;

/**
 * @author weixiaochun
 * @date 2022/5/28 16:06
 */
public class ESClient {

    private RestHighLevelClient esClient;

    @Before
    public void initES() {
        // 创建ES客户端
        esClient = new RestHighLevelClient(
                RestClient.builder(new HttpHost("192.168.56.100", 9200, "http"))
        );
    }

    /**
     * 创建索引
     */
    @Test
    public void createIndex() throws IOException {

        CreateIndexRequest request = new CreateIndexRequest("user");
        CreateIndexResponse response = esClient.indices()
                .create(request, RequestOptions.DEFAULT);

        // 响应状态
        boolean acknowledged = response.isAcknowledged();

        System.out.println(acknowledged);
    }

    /**
     * 查询索引
     */
    @Test
    public void searchIndex() throws IOException {
        GetIndexRequest request = new GetIndexRequest("user");
        GetIndexResponse response = esClient.indices()
                .get(request, RequestOptions.DEFAULT);

        System.out.println(response.getAliases());
        System.out.println(response.getMappings());
        System.out.println(response.getSettings());
    }

    /**
     * 删除索引
     */
    @Test
    public void deleteIndex() throws IOException {
        DeleteIndexRequest request = new DeleteIndexRequest("user");
        AcknowledgedResponse response = esClient.indices()
                .delete(request, RequestOptions.DEFAULT);

        boolean acknowledged = response.isAcknowledged();

        System.out.println(acknowledged);
    }

    /**
     * 插入文档数据
     */
    @Test
    public void insertDoc() throws IOException {
        IndexRequest request = new IndexRequest();

        // index：索引 id：ID
        request.index("user")
                .id("1001");

        User user = new User();
        user.setName("张三");
        user.setSex("男");
        user.setAge(30);

        // 向ES插入数据，必须将数据转换为Json格式
        ObjectMapper mapper = new ObjectMapper();
        String userJson = mapper.writeValueAsString(user);

        // 数据
        request.source(userJson, XContentType.JSON);

        IndexResponse response = esClient.index(request, RequestOptions.DEFAULT);

        System.out.println(response.getResult());
    }

    /**
     * 修改文档数据
     */
    @Test
    public void updateDoc() throws IOException {

        UpdateRequest request = new UpdateRequest();
        request.index("user").id("1001");

        request.doc(XContentType.JSON, "sex", "女");


        UpdateResponse response = esClient.update(request, RequestOptions.DEFAULT);
    }

    /**
     * 查询文档数据
     */
    @Test
    public void getDoc() throws IOException {

        GetRequest request = new GetRequest();

        request.index("user").id("1001");

        GetResponse response = esClient.get(request, RequestOptions.DEFAULT);

        System.out.println(response.getSourceAsString());
    }

    /**
     * 删除文档数据
     */
    @Test
    public void deleteDoc() throws IOException {

        DeleteRequest request = new DeleteRequest();
        request.index("user").id("1001");

        DeleteResponse response = esClient.delete(request, RequestOptions.DEFAULT);

        System.out.println(response.getResult());
    }

    /**
     * 批量插入文档数据
     */
    @Test
    public void batchInsertDoc() throws IOException {

        BulkRequest request = new BulkRequest();

        request.add(new IndexRequest()
                .index("user")
                .id("1001")
                .source(XContentType.JSON, "name", "zhangsan", "age", 30, "sex", "男"));
        request.add(new IndexRequest()
                .index("user")
                .id("1002")
                .source(XContentType.JSON, "name", "lisi", "age", 30, "sex", "女"));
        request.add(new IndexRequest()
                .index("user")
                .id("1003")
                .source(XContentType.JSON, "name", "wangwu", "age", 40, "sex", "男"));
        request.add(new IndexRequest()
                .index("user")
                .id("1004")
                .source(XContentType.JSON, "name", "wangwu1", "age", 40, "sex", "女"));
        request.add(new IndexRequest()
                .index("user")
                .id("1005")
                .source(XContentType.JSON, "name", "wangwu2", "age", 50, "sex", "男"));
        request.add(new IndexRequest()
                .index("user")
                .id("1006")
                .source(XContentType.JSON, "name", "wangwu3", "age", 50, "sex", "男"));

        BulkResponse responses = esClient.bulk(request, RequestOptions.DEFAULT);

        System.out.println(responses.getTook());
        System.out.println(responses.getItems());
    }

    /**
     * 批量删除文档数据
     */
    @Test
    public void batchDeleteDoc() throws IOException {

        BulkRequest request = new BulkRequest();

        request.add(new DeleteRequest().index("user").id("1001"));
        request.add(new DeleteRequest().index("user").id("1002"));
        request.add(new DeleteRequest().index("user").id("1003"));

        BulkResponse responses = esClient.bulk(request, RequestOptions.DEFAULT);

        for (BulkItemResponse item : responses.getItems()) {
            System.out.println(item);
        }
    }

    /**
     * 高级全量查询文档数据
     */
    @Test
    public void queryDoc() throws IOException {

        SearchRequest request = new SearchRequest();

        request.indices("user");

        // 构造条件
        SearchSourceBuilder builder = new SearchSourceBuilder().query(QueryBuilders.matchAllQuery());

        request.source(builder);

        SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);

        SearchHits hits = response.getHits();

        System.out.println("条数：" + hits.getTotalHits());
        System.out.println("耗时：" + response.getTook());

        for (SearchHit hit : hits.getHits()) {
            System.out.println(hit.getSourceAsString());
        }
    }

    /**
     * 高级条件查询文档数据
     */
    @Test
    public  void queryOptionsDoc() throws IOException {

        SearchRequest request = new SearchRequest();

        request.indices("user");

        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(QueryBuilders.termQuery("age", 30));

        request.source(builder);

        SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);

        SearchHits hits = response.getHits();

        System.out.println("条数：" + hits.getTotalHits());
        System.out.println("耗时：" + response.getTook());

        for (SearchHit hit : hits.getHits()) {
            System.out.println(hit.getSourceAsString());
        }

    }

    /**
     * 高级分页查询文档数据
     */
    @Test
    public void queryPageDoc() throws IOException {

        SearchRequest request = new SearchRequest();

        request.indices("user");

        SearchSourceBuilder builder = new SearchSourceBuilder();

        builder.query(QueryBuilders.matchAllQuery());
        builder.from(0).size(2);

        request.source(builder);


        SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);

        SearchHits hits = response.getHits();

        System.out.println("条数：" + hits.getTotalHits());
        System.out.println("耗时：" + response.getTook());

        for (SearchHit hit : hits.getHits()) {
            System.out.println(hit.getSourceAsString());
        }
    }

    /**
     * 高级排序查询文档数据
     */
    @Test
    public void querySortDoc() throws IOException {

        SearchRequest request = new SearchRequest();

        request.indices("user");

        SearchSourceBuilder builder = new SearchSourceBuilder();

        builder.query(QueryBuilders.matchAllQuery());
        builder.sort("age", SortOrder.DESC);

        request.source(builder);

        SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);

        SearchHits hits = response.getHits();

        System.out.println("条数：" + hits.getTotalHits());
        System.out.println("耗时：" + response.getTook());

        for (SearchHit hit : hits) {
            System.out.println(hit.getSourceAsString());
        }
    }

    /**
     * 高级指定字段查询文档数据
     */
    @Test
    public void queryFieldDoc() throws IOException {

        SearchRequest request = new SearchRequest();

        request.indices("user");

        SearchSourceBuilder builder = new SearchSourceBuilder();

        String[] excludes = {"age"};
        String[] includes = {};
        builder.fetchSource(includes, excludes);

        request.source(builder);

        SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);

        SearchHits hits = response.getHits();

        System.out.println("条数：" + hits.getTotalHits());
        System.out.println("耗时：" + response.getTook());

        for (SearchHit hit : hits) {
            System.out.println(hit.getSourceAsString());
        }
    }

    /**
     * 高级组合查询文档数据
     */
    @Test
    public void queryCombinationDoc() throws IOException {

        SearchRequest request = new SearchRequest();

        request.indices("user");

        SearchSourceBuilder builder = new SearchSourceBuilder();

        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        boolQuery.must(QueryBuilders.matchQuery("age", 30));
//        boolQuery.must(QueryBuilders.matchQuery("sex", "男"));
        boolQuery.mustNot(QueryBuilders.matchQuery("sex", "男"));

        builder.query(boolQuery);

        request.source(builder);

        SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);

        SearchHits hits = response.getHits();

        System.out.println("条数：" + hits.getTotalHits());
        System.out.println("耗时：" + response.getTook());

        for (SearchHit hit : hits) {
            System.out.println(hit.getSourceAsString());
        }
    }

    /**
     * 高级范围查询文档数据
     */
    @Test
    public void queryRangeDoc() throws IOException {

        SearchRequest request = new SearchRequest();

        request.indices("user");

        SearchSourceBuilder builder = new SearchSourceBuilder();

        RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("age");
        rangeQueryBuilder.gte(30);
        rangeQueryBuilder.lte(40);

        builder.query(rangeQueryBuilder);

        request.source(builder);

        SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);

        SearchHits hits = response.getHits();

        System.out.println("条数：" + hits.getTotalHits());
        System.out.println("耗时：" + response.getTook());

        for (SearchHit hit : hits) {
            System.out.println(hit.getSourceAsString());
        }
    }

    /**
     * 高级模糊查询文档数据
     */
    @Test
    public void queryFuzzyDoc() throws IOException {

        SearchRequest request = new SearchRequest();

        request.indices("user");

        SearchSourceBuilder builder = new SearchSourceBuilder();

        // 模糊查询 name：wangwu 相差1个字符的数据
        FuzzyQueryBuilder fuzzyQueryBuilder = QueryBuilders.fuzzyQuery("name", "wangwu")
                .fuzziness(Fuzziness.ONE);

        builder.query(fuzzyQueryBuilder);

        request.source(builder);

        SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);

        SearchHits hits = response.getHits();

        System.out.println("条数：" + hits.getTotalHits());
        System.out.println("耗时：" + response.getTook());

        for (SearchHit hit : hits) {
            System.out.println(hit.getSourceAsString());
        }
    }

    /**
     * 高级高亮查询文档数据
     */
    @Test
    public void queryHighLightDoc() throws IOException {

        SearchRequest request = new SearchRequest();

        request.indices("user");

        SearchSourceBuilder builder = new SearchSourceBuilder();

        HighlightBuilder highlightBuilder = new HighlightBuilder();

        highlightBuilder.preTags("<font color = 'red'>");
        highlightBuilder.postTags("</font>");
        highlightBuilder.field("name");

        builder.query(QueryBuilders.termQuery("name", "zhangsan"))
                .highlighter(highlightBuilder);

        request.source(builder);

        SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);

        SearchHits hits = response.getHits();

        System.out.println("条数：" + hits.getTotalHits());
        System.out.println("耗时：" + response.getTook());

        System.out.println(response);

        for (SearchHit hit : hits) {
            System.out.println(hit.getSourceAsString());
            System.out.println(hit.getHighlightFields().get("name").getFragments());
        }
    }

    /**
     * 高级聚合查询文档数据
     */
    @Test
    public void queryAggregationDoc() throws IOException {

        SearchRequest request = new SearchRequest();

        request.indices("user");

        SearchSourceBuilder builder = new SearchSourceBuilder();

        MaxAggregationBuilder maxAggregationBuilder = AggregationBuilders
                .max("maxAge").field("age");

        builder.aggregation(maxAggregationBuilder);

        request.source(builder);

        SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);

        SearchHits hits = response.getHits();

        System.out.println("条数：" + hits.getTotalHits());
        System.out.println("耗时：" + response.getTook());

        System.out.println(response);

        for (SearchHit hit : hits) {
            System.out.println(hit.getSourceAsString());
        }

        for (Aggregation aggregation : response.getAggregations()) {
            System.out.println(aggregation.getName());
        }
    }


    @After
    public void destroy() throws IOException {

        // 关闭ES客户端
        esClient.close();
    }
}
